use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::rc::Rc;
use chrono::Local;
use crate::business::app_state::AppState;
use crate::business::rpc::service::rpc_message_service::RpcMessageService;
use crate::business::share::dto::RefMessageData;
use crate::util::const_var::MESSAGE_SPIT;
use crate::business::util::local_seq::local_seq;
use crate::business::websocket::dto::common_dto::OkListResp;
use crate::business::websocket::dto::im_message_dto::{MessageObject, MessageObjectsReq};
use crate::db::db::Db;
use crate::db::pojo::pojo::{ImMessage, ImMessageActionData, ImMessageActionStatus, ImMessageFileStatus, ImMessageSend, ImMessageStatus, ImSession, ImSessionStatus, MessageType};
use crate::db::service::im_group_service::ImGroupService;
use crate::db::service::im_message_service::ImMessageService;
use crate::db::service::im_session_service::ImSessionService;

pub struct MessageSendService;

impl MessageSendService {

    pub async fn send_message(app_state: AppState, mut sessions: Vec<ImSession>, mut messages: &mut Vec<ImMessage>) {
        let db = Db::open();
        let session_service = ImSessionService;
        session_service.updates2(db.clone(), &mut sessions);

        let message_service = ImMessageService;
        message_service.inserts(db.clone(), &mut messages);

        let message_objects = messages.iter().map(|message| MessageObject::from(message)).collect::<Vec<MessageObject>>();
        let message_objects_req = MessageObjectsReq {
            message_objects,
            create_date_time: Local::now(),
            local_seq: "".to_string(),
        };
        let send_message_result = RpcMessageService::send_messages(app_state, message_objects_req).await;
        match send_message_result{
            Ok(ok_list_resp) => {
                log::info!("message send success, {:?}", ok_list_resp);
                MessageSendService::do_send_success(ok_list_resp, messages);
            }
            err => {
                log::error!("send message error: {:?}", err);
            }
        }
    }

    pub async fn send_messages(app_state: AppState, messages: &mut Vec<ImMessage>) {
        let message_objects = messages.iter().map(|message| MessageObject::from(message)).collect::<Vec<MessageObject>>();
        let message_objects_req = MessageObjectsReq {
            message_objects,
            create_date_time: Local::now(),
            local_seq: "".to_string(),
        };
        let send_message_result = RpcMessageService::send_messages(app_state, message_objects_req).await;
        match send_message_result{
            Ok(ok_list_resp) => {
                log::info!("message send success, {:?}", ok_list_resp);
                MessageSendService::do_send_success(ok_list_resp, messages);
            }
            err => {
                log::error!("send message error: {:?}", err);
            }
        }
    }

    pub fn build_message(session: Rc<RefCell<ImSession>>, content: String, ref_message: Option<RefMessageData>) -> ImMessage {
        let user_id = session.clone().borrow().current_user_id.clone();
        let (ref_type, ref_message_ids) = match ref_message {
            None => {
                (None, None)
            }
            Some(ref_message) => {
                (Some(ref_message.ref_type), Some(ref_message.ref_id))
            }
        };
        let message_send_list = match session.clone().borrow().group.clone() {
            None => {
                match session.clone().borrow().group_code.clone() {
                    None => {HashSet::new()}
                    Some(group_code) => {
                        let group_service = ImGroupService;
                        let group = group_service.query_group(&group_code);
                        match group {
                            Some(group) => {
                                match group.group_users {
                                    None => {HashSet::new()}
                                    Some(group_users) => {
                                        group_users.into_iter().map(|group_user| ImMessageSend::new(group_user.user_id)).collect::<HashSet<ImMessageSend>>()
                                    }
                                }
                            }
                            None => {HashSet::new()}
                        }
                    }
                }
            }
            Some(group) => {
                if let Some(group_users) = group.group_users.clone()  {
                    group_users.iter().map(|group_user| ImMessageSend::new(group_user.user_id.clone())).collect::<HashSet<ImMessageSend>>()
                } else {
                    HashSet::new()
                }
            }
        };

        let session_id = session.clone().borrow().id.clone().unwrap();
        ImMessage {
            id: None,
            client_id: local_seq(&user_id),
            current_user_id: user_id.clone(),
            from_user_id: user_id,
            to_user_id: session.borrow().to_user_id.clone(),
            server_id: None,
            message_type: MessageType::Text,
            group_code: session.borrow().group_code.clone(),
            content,
            session_id,
            ref_type,
            ref_message_ids,
            ext: None,
            ext1: None,
            ext2: None,
            version: 0,
            status: ImMessageStatus::Created,
            file_status: ImMessageFileStatus::None,
            action_status: ImMessageActionStatus::None,
            server_receive_time: None,
            create_date_time: Local::now(),
            update_date_time: Local::now(),
            message_send_set: Some(message_send_list),
            session: Some(session.clone().borrow().clone()),
        }
    }

    fn do_send_success(ok_list_resp: OkListResp, messages: &mut Vec<ImMessage>) {
        let message_service = ImMessageService;

        let update_messages = MessageSendService::do_send_message_success(ok_list_resp, messages);

        let mut message_send_list = vec![];

        for message in update_messages {
            if message.is_p2p() { continue; }

            let message_send = message_service.query_message_send_by_user_id(message.id.unwrap(), &message.current_user_id);
            if let Some(message_send) = message_send {
                let message_action_data = ImMessageActionData {
                    message_id: message.id.unwrap(),
                    user_id: message.current_user_id.clone(),
                    action_status: ImMessageActionStatus::Readed,
                };
                message_send_list.push(message_action_data);
            }
        }

        message_service.update_message_sends(message_send_list);

        // todo
        // send file
    }


    fn do_send_message_success(ok_list_resp: OkListResp, messages: &mut Vec<ImMessage>)-> Vec<&mut ImMessage> {
        let db = Db::open();

        let message_service = ImMessageService;
        let session_service = ImSessionService;

        let resp_map: HashMap<_, _> = ok_list_resp.local_seq_set.into_iter().map(|res| {
            let ids = res.split(MESSAGE_SPIT).collect::<Vec<&str>>();
            (ids[0].to_string(), (ids[0].to_string(), ids[1].to_string(), ids[2].to_string()))
        }).collect();

        let receive_date_time = ok_list_resp.success_data_time;

        let mut update_message_list = Vec::new();
        let mut update_session_list = Vec::new();

        for message in messages {
            let client_id = message.client_id.clone();
            let (_, server_id, session_id) = resp_map.get(&client_id).unwrap();

            log::info!("send message info: {:?}", message);
            let user_id = message.current_user_id.clone();
            let from_user_id = message.from_user_id.clone();
            let to_user_id = message.to_user_id.clone();
            let group_code = message.group_code.clone();

            message.status = ImMessageStatus::Sended;
            message.server_id = Some(String::from(server_id));
            message.server_receive_time = Some(receive_date_time.clone());
            message.update_date_time = Local::now();
            update_message_list.push(message);

            let session = if (&to_user_id).is_some() {
                session_service.get_by_user_id(&user_id, &from_user_id, &to_user_id.unwrap())
            } else {
                session_service.get_by_group_code_and_user_id(&group_code.unwrap(), &user_id)
            };

            if let Some(mut session) = session {
                let session_status = session.status.clone();

                if session.server_id.is_none() {
                    session.server_id = Some(session_id.to_string());
                    session.update_time = Local::now();

                    if session_status == ImSessionStatus::Created {
                        session.status = ImSessionStatus::Enable;
                    }

                    update_session_list.push(session);
                } else if session_status == ImSessionStatus::Created {
                    session.status = ImSessionStatus::Enable;
                    session.update_time = Local::now();

                    update_session_list.push(session);
                }
            }
        }

        message_service.updates(db.clone(), &mut update_message_list);

        let mut sessions = update_session_list.iter_mut().collect::<Vec<&mut ImSession>>();
        session_service.updates(&mut sessions);

        update_message_list
    }
}